home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Overload Trio 2
/
Shareware Overload Trio Volume 2 (Chestnut CD-ROM).ISO
/
dir24
/
jnos110g.zip
/
TELNET.C
< prev
next >
Wrap
C/C++ Source or Header
|
1994-04-17
|
15KB
|
574 lines
/* Internet Telnet client
* Copyright 1991 Phil Karn, KA9Q
*/
/* Mods by PA0GRI */
#ifdef __TURBOC__
#include <io.h>
#include <fcntl.h>
#endif
#include "global.h"
#include "mbuf.h"
#include "socket.h"
#include "telnet.h"
#include "session.h"
#include "proc.h"
#include "tty.h"
#include "commands.h"
#include "netuser.h"
static int filemode __ARGS((FILE *fp,int mode));
#define CTLZ 26
int Refuse_echo = 0;
int Tn_cr_mode = 0; /* if true turn <cr> to <cr-nul> */
#undef DEBUG 1
#ifdef DEBUG
char *T_options[] = {
"Transmit Binary", /* 0 */
"Echo", /* 1 */
"", /* 2 */
"Suppress Go Ahead", /* 3 */
"", /* 4 */
"Status", /* 5 */
"Timing Mark" /* 6 */
#ifdef TN_KK6JQ
,
"Remote Controlled Transmission/Echo",
"Negotiate Line Width",
"Negotiate Page Size",
"Negotiate CR Disposition",
"Negotiate Horz Tab Stops",
"Negotiate Horz tab Disposition",
"Negotiate FormFeed Disposition",
"Negotiate Vert Tab Stops",
"Negotiate Vert Tab Disposition",
"Negotiate LineFeed Disposition",
"Extended ASCII",
"Force Logout",
"Byte Macro",
"Data Entry Terminal",
"Protocol supdup",
"supdup",
"Send Location",
"Terminal Type",
"End of Record"
#endif /* TN_KK6JQ */
};
#endif /* DEBUG */
#if defined BBSSESSION || defined TELNETSESSION || defined TTYLINKSESSION
/* Execute user telnet,ttylink or bbs command */
int
dotelnet(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct session *sp;
struct sockaddr_in fsocket;
char *name;
int split = 0;
int bbs = 0;
/*Make sure this comes from console - WG7J*/
if(Curproc->input != Command->input)
return 0;
name = argv[1]; /* This is not valid for 'bbs' command ! */
#ifdef BBSSESSION
if(*argv[0] == 'b') {
name = "Local BBS";
bbs = 1;
}
#ifdef TTYLINKSESSION
else
#endif
#endif
#ifdef TTYLINKSESSION
if((strlen(argv[0]) > 1) && (argv[0][1] == 't')) /* tty-link command */
split = 1;
#endif
/* Allocate a session descriptor */
if((sp = newsession(name,TELNET,split)) == NULLSESSION){
tputs(TooManySessions);
return 1;
}
fsocket.sin_family = AF_INET;
if(argc < 3) {
if(split)
fsocket.sin_port = IPPORT_TTYLINK;
else
fsocket.sin_port = IPPORT_TELNET;
} else {
fsocket.sin_port = atoip(argv[2]);
}
#ifdef BBSSESSION
if(bbs) {
/* 127.0.0.1 is the loopback interface */
fsocket.sin_addr.s_addr = 0x7f000001L;
} else
#endif
{
tprintf("Resolving %s... ",sp->name);
if((fsocket.sin_addr.s_addr = resolve(sp->name)) == 0){
tprintf(Badhost,sp->name);
keywait(NULLCHAR,1);
freesession(sp);
return 1;
}
}
if((sp->s = socket(AF_INET,SOCK_STREAM,0)) == -1){
tputs(Nosock);
keywait(NULLCHAR,1);
freesession(sp);
return 1;
}
return tel_connect(sp,(char *)&fsocket,SOCKSIZE);
}
#endif /* TELNET || TTYLINK || BBS */
/* Generic interactive connect routine, used by Telnet, AX.25, NET/ROM */
int
tel_connect(sp,fsocket,len)
struct session *sp;
char *fsocket;
int len;
{
unsigned int index;
struct telnet tn;
index = (unsigned int) (sp - Sessions);
memset((char *)&tn,0,sizeof(tn));
tn.eolmode = Tn_cr_mode;
tn.session = sp; /* Upward pointer */
sp->cb.telnet = &tn; /* Downward pointer */
sockmode(sp->s,SOCK_ASCII); /* Default to ascii mode */
tprintf("Trying %s...\n",psocket((struct sockaddr *)fsocket));
if(connect(sp->s,fsocket,len) == -1){
tprintf("%s session %u failed: %s errno %d\n",
Sestypes[sp->type], index, sockerr(sp->s),errno);
keywait(NULLCHAR,1);
freesession(sp);
return 1;
}
tprintf("%s session %u connected to %s\n",
Sestypes[sp->type],index,sp->name);
tnrecv(&tn);
return 0;
}
/* Telnet input routine, common to both telnet and ttylink */
void
tnrecv(tn)
struct telnet *tn;
{
int c,s,index;
struct session *sp;
char *cp;
sp = tn->session;
s = sp->s;
index = (unsigned int) (sp - Sessions);
/* Fork off the transmit process */
sp->proc1 = newproc("tel_out",1024,tel_output,0,tn,NULL,0);
/* Process input on the connection */
while((c = recvchar(s)) != -1){
if(c != IAC){
#ifdef notdef
/* Allow international character sets to pass - WG7J */
/* Ordinary character */
if(!tn->remote[TN_TRANSMIT_BINARY])
c &= 0x7f;
#endif
tputc((char)c);
continue;
}
/* IAC received, get command sequence */
c = recvchar(s);
switch(c){
case WILL:
c = recvchar(s);
willopt(tn,c);
break;
case WONT:
c = recvchar(s);
wontopt(tn,c);
break;
case DO:
c = recvchar(s);
doopt(tn,c);
break;
case DONT:
c = recvchar(s);
dontopt(tn,c);
break;
#ifdef TN_KK6JQ
case SB:
c = recvchar(s);
dosb(tn,c);
break;
#endif /* TN_KK6JQ */
case IAC: /* Escaped IAC */
tputc(IAC);
break;
}
}
/* A close was received from the remote host.
* Notify the user, kill the output task and wait for a response
* from the user before freeing the session.
*/
sockmode(sp->output,SOCK_ASCII); /* Restore newline translation */
cp = sockerr(s);
tprintf("%s session %u", Sestypes[sp->type],index);
tprintf(" closed: %s\n", cp != NULLCHAR ? cp : "EOF");
killproc(sp->proc1);
sp->proc1 = NULLPROC;
close_s(sp->s);
sp->s = -1;
keywait(NULLCHAR,1);
freesession(sp);
}
/* User telnet output task, started by user telnet command */
void
tel_output(unused,tn1,p)
int unused;
void *tn1;
void *p;
{
struct session *sp;
int c;
struct telnet *tn;
tn = (struct telnet *)tn1;
sp = tn->session;
/* Send whatever's typed on the terminal */
while((c = recvchar(sp->input)) != EOF){
usputc(sp->s,(char)c);
if(!tn->remote[TN_ECHO] && sp->record != NULLFILE)
putc(c,sp->record);
/* By default, output is transparent in remote echo mode.
* If eolmode is set, turn a cr into cr-null.
* This can only happen when in remote echo (raw) mode, since
* the tty driver normally maps \r to \n in cooked mode.
*/
if(c == '\r' && tn->eolmode)
usputc(sp->s,'\0');
if(tn->remote[TN_ECHO])
usflush(sp->s);
}
/* Make sure our parent doesn't try to kill us after we exit */
sp->proc1 = NULLPROC;
}
int
doecho(argc,argv,p)
int argc;
char *argv[];
void *p;
{
if(argc < 2){
if(Refuse_echo)
tputs("Refuse\n");
else
tputs("Accept\n");
} else {
if(argv[1][0] == 'r')
Refuse_echo = 1;
else if(argv[1][0] == 'a')
Refuse_echo = 0;
else
return -1;
}
return 0;
}
/* set for unix end of line for remote echo mode telnet */
int
doeol(argc,argv,p)
int argc;
char *argv[];
void *p;
{
if(argc < 2){
if(Tn_cr_mode)
tputs("null\n");
else
tputs("standard\n");
} else {
if(argv[1][0] == 'n')
Tn_cr_mode = 1;
else if(argv[1][0] == 's')
Tn_cr_mode = 0;
else {
tprintf("Usage: %s [standard|null]\n",argv[0]);
return -1;
}
}
return 0;
}
/* The guts of the actual Telnet protocol: negotiating options */
void
willopt(tn,opt)
struct telnet *tn;
int opt;
{
int ack;
#ifdef DEBUG
printf("recv: will ");
if(uchar(opt) <= NOPTIONS)
printf("%s\n",T_options[opt]);
else
printf("%u\n",opt);
#endif
switch(uchar(opt)){
case TN_TRANSMIT_BINARY:
case TN_ECHO:
case TN_SUPPRESS_GA:
if(tn->remote[uchar(opt)] == 1)
return; /* Already set, ignore to prevent loop */
if(uchar(opt) == TN_ECHO){
if(Refuse_echo){
/* User doesn't want to accept */
ack = DONT;
break;
} else {
/* Put tty into raw mode */
tn->session->ttystate.edit = 0;
tn->session->ttystate.echo = 0;
sockmode(tn->session->s,SOCK_BINARY);
sockmode(tn->session->input,SOCK_BINARY);
sockmode(tn->session->output,SOCK_BINARY);
if(tn->session->record != NULLFILE)
filemode(tn->session->record,SOCK_BINARY);
}
}
tn->remote[uchar(opt)] = 1;
ack = DO;
break;
#ifdef TN_KK6JQ
case TN_TERM_TYPE: /* We are the client, we don't want this */
#endif /* TN_KK6JQ */
default:
ack = DONT; /* We don't know what he's offering; refuse */
}
answer(tn,ack,opt);
}
void
wontopt(tn,opt)
struct telnet *tn;
int opt;
{
#ifdef DEBUG
printf("recv: wont ");
if(uchar(opt) <= NOPTIONS)
printf("%s\n",T_options[uchar(opt)]);
else
printf("%u\n",uchar(opt));
#endif
if(uchar(opt) <= NOPTIONS){
if(tn->remote[uchar(opt)] == 0)
return; /* Already clear, ignore to prevent loop */
tn->remote[uchar(opt)] = 0;
if(uchar(opt) == TN_ECHO){
/* Put tty into cooked mode */
tn->session->ttystate.edit = 1;
tn->session->ttystate.echo = 1;
sockmode(tn->session->s,SOCK_ASCII);
sockmode(tn->session->input,SOCK_ASCII);
sockmode(tn->session->output,SOCK_ASCII);
if(tn->session->record != NULLFILE)
filemode(tn->session->record,SOCK_ASCII);
}
}
answer(tn,DONT,opt); /* Must always accept */
}
#ifdef TN_KK6JQ
void
dosb(tn, opt)
struct telnet *tn;
int opt;
{
struct session *sp;
int s, c;
char *name, resp_buf[64];
int resp_len = 0;
sp = tn->session;
s = sp->s;
switch (uchar(opt)) {
case TN_TERM_TYPE:
/* make sure qualifier is SEND */
/* ignore otherwise */
/* Karn code is cavalier about EOF when in an IAC sequence.. */
c = recvchar(s);
if (c == TS_SEND) {
c = recvchar(s); /* should be IAC */
c = recvchar(s); /* should be SE */
/*
* Should check to make sure sequence includes IAC, SE and somehow fail
* if it doesn't.
*/
name = getenv("TERM");
if ((name==NULL) || ((resp_len = strlen(name)) > 58))
name = "UNKNOWN";
sprintf(resp_buf, "%c%c%c%c%s%c%c",
IAC, SB, TN_TERM_TYPE, TS_IS, name,
IAC, SE);
/*
original code:
resp_len += 6;
Oops! What is the REAL length of this string? It's not just the control
characters... the length of the terminal name needs to be added in
*/
resp_len += strlen(resp_buf);
}
break;
default:
break;
}
if (resp_len > 0)
send(s, resp_buf, resp_len, 0);
}
#endif /* TN_KK6JQ */
void
doopt(tn,opt)
struct telnet *tn;
int opt;
{
int ack;
#ifdef DEBUG
printf("recv: do ");
if(uchar(opt) <= NOPTIONS)
printf("%s\n",T_options[uchar(opt)]);
else
printf("%u\n",uchar(opt));
#endif
switch(uchar(opt)){
case TN_SUPPRESS_GA:
#ifdef TN_KK6JQ
case TN_TERM_TYPE:
#endif /* TN_KK6JQ */
if(tn->local[uchar(opt)] == 1)
return; /* Already set, ignore to prevent loop */
tn->local[uchar(opt)] = 1;
ack = WILL;
break;
default:
ack = WONT; /* Don't know what it is */
}
answer(tn,ack,opt);
}
void
dontopt(tn,opt)
struct telnet *tn;
int opt;
{
#ifdef DEBUG
printf("recv: dont ");
if(uchar(opt) <= NOPTIONS)
printf("%s\n",T_options[uchar(opt)]);
else
printf("%u\n",uchar(opt));
#endif
if(uchar(opt) <= NOPTIONS){
if(tn->local[uchar(opt)] == 0){
/* Already clear, ignore to prevent loop */
return;
}
tn->local[uchar(opt)] = 0;
}
answer(tn,WONT,opt);
}
void
answer(tn,r1,r2)
struct telnet *tn;
int r1,r2;
{
char s[3];
#ifdef DEBUG
switch(r1){
case WILL:
printf("sent: will ");
break;
case WONT:
printf("sent: wont ");
break;
case DO:
printf("sent: do ");
break;
case DONT:
printf("sent: dont ");
break;
}
if(r2 <= NOPTIONS)
printf("%s\n",T_options[r2]);
else
printf("%u\n",r2);
#endif
s[0] = IAC;
s[1] = r1;
s[2] = r2;
send(tn->session->s,s,3,0);
}
#ifdef __TURBOC__
/* Set end-of-line translation mode on file */
static int
filemode(fp,mode)
FILE *fp;
int mode;
{
int omode;
if(fp == NULLFILE)
return -1;
if(fp->flags & _F_BIN)
omode = SOCK_BINARY;
else
omode = SOCK_ASCII;
switch(mode){
case SOCK_BINARY:
fp->flags = _F_BIN;
setmode(fileno(fp),O_BINARY);
break;
case SOCK_ASCII:
fp->flags &= ~_F_BIN;
setmode(fileno(fp),O_TEXT);
break;
}
return omode;
}
#else
static int
filemode(fp,mode)
FILE *fp;
int mode;
{
return 0;
}
#endif